<!DOCTYPE html>
<html>

<head>

<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
<title>jd v1</title>


<style type="text/css">
*{margin:0;padding:0;}
body {
	font:13.34px helvetica,arial,freesans,clean,sans-serif;
	color:black;
	line-height:1.4em;
	background-color: #F8F8F8;
	padding: 0.7em;
}
p {
	margin:1em 0;
	line-height:1.5em;
}
table {
	font-size:inherit;
	font:100%;
	margin:1em;
}
table th{border-bottom:1px solid #bbb;padding:.2em 1em;}
table td{border-bottom:1px solid #ddd;padding:.2em 1em;}
input[type=text],input[type=password],input[type=image],textarea{font:99% helvetica,arial,freesans,sans-serif;}
select,option{padding:0 .25em;}
optgroup{margin-top:.5em;}
pre,code{font:12px Monaco,"Courier New","DejaVu Sans Mono","Bitstream Vera Sans Mono",monospace;}
pre {
	margin:1em 0;
	font-size:12px;
	background-color:#eee;
	border:1px solid #ddd;
	padding:5px;
	line-height:1.5em;
	color:#444;
	overflow:auto;
	-webkit-box-shadow:rgba(0,0,0,0.07) 0 1px 2px inset;
	-webkit-border-radius:3px;
	-moz-border-radius:3px;border-radius:3px;
}
pre code {
	padding:0;
	font-size:12px;
	background-color:#eee;
	border:none;
}
code {
	font-size:12px;
	background-color:#f8f8ff;
	color:#444;
	padding:0 .2em;
	border:1px solid #dedede;
}
img{border:0;max-width:100%;}
abbr{border-bottom:none;}
a{color:#4183c4;text-decoration:none;}
a:hover{text-decoration:underline;}
a code,a:link code,a:visited code{color:#4183c4;}
h2,h3{margin:1em 0;}
h1,h2,h3,h4,h5,h6{border:0;}
h1{font-size:170%;border-top:4px solid #aaa;padding-top:.5em;margin-top:1.5em;}
h1:first-child{margin-top:0;padding-top:.25em;border-top:none;}
h2{font-size:150%;margin-top:1.5em;border-top:4px solid #e0e0e0;padding-top:.5em;}
h3{margin-top:1em;}
hr{border:1px solid #ddd;}
ul{margin:1em 0 1em 2em;}
ol{margin:1em 0 1em 2em;}
ul li,ol li{margin-top:.5em;margin-bottom:.5em;}
ul ul,ul ol,ol ol,ol ul{margin-top:0;margin-bottom:0;}
blockquote{margin:1em 0;border-left:5px solid #ddd;padding-left:.6em;color:#555;}
dt{font-weight:bold;margin-left:1em;}
dd{margin-left:2em;margin-bottom:1em;}
sup {
    font-size: 0.83em;
    vertical-align: super;
    line-height: 0;
}
kbd {
  display: inline-block;padding: 3px 5px;font-size: 11px;line-height: 10px;color: #555;vertical-align: middle;background-color: #fcfcfc;border: solid 1px #ccc;border-bottom-color: #bbb;border-radius: 3px;box-shadow: inset 0 -1px 0 #bbb;
}
* {
	-webkit-print-color-adjust: exact;
}
@media screen and (min-width: 914px) {
    body {
        width: 854px;
        margin:0 auto;
    }
}
@media print {
	table, pre {
		page-break-inside: avoid;
	}
	pre {
		word-wrap: break-word;
	}
}
</style>

<style type="text/css">
/**
 * prism.js default theme for JavaScript, CSS and HTML
 * Based on dabblet (http://dabblet.com)
 * @author Lea Verou
 */

code[class*="language-"],
pre[class*="language-"] {
	color: black;
	background: none;
	text-shadow: 0 1px white;
	font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
	text-align: left;
	white-space: pre;
	word-spacing: normal;
	word-break: normal;
	word-wrap: normal;
	line-height: 1.5;

	-moz-tab-size: 4;
	-o-tab-size: 4;
	tab-size: 4;

	-webkit-hyphens: none;
	-moz-hyphens: none;
	-ms-hyphens: none;
	hyphens: none;
}

pre[class*="language-"]::-moz-selection, pre[class*="language-"] ::-moz-selection,
code[class*="language-"]::-moz-selection, code[class*="language-"] ::-moz-selection {
	text-shadow: none;
	background: #b3d4fc;
}

pre[class*="language-"]::selection, pre[class*="language-"] ::selection,
code[class*="language-"]::selection, code[class*="language-"] ::selection {
	text-shadow: none;
	background: #b3d4fc;
}

@media print {
	code[class*="language-"],
	pre[class*="language-"] {
		text-shadow: none;
	}
}

/* Code blocks */
pre[class*="language-"] {
	padding: 1em;
	margin: .5em 0;
	overflow: auto;
}

:not(pre) > code[class*="language-"],
pre[class*="language-"] {
	background: #f5f2f0;
}

/* Inline code */
:not(pre) > code[class*="language-"] {
	padding: .1em;
	border-radius: .3em;
	white-space: normal;
}

.token.comment,
.token.prolog,
.token.doctype,
.token.cdata {
	color: slategray;
}

.token.punctuation {
	color: #999;
}

.namespace {
	opacity: .7;
}

.token.property,
.token.tag,
.token.boolean,
.token.number,
.token.constant,
.token.symbol,
.token.deleted {
	color: #905;
}

.token.selector,
.token.attr-name,
.token.string,
.token.char,
.token.builtin,
.token.inserted {
	color: #690;
}

.token.operator,
.token.entity,
.token.url,
.language-css .token.string,
.style .token.string {
	color: #a67f59;
	background: hsla(0, 0%, 100%, .5);
}

.token.atrule,
.token.attr-value,
.token.keyword {
	color: #07a;
}

.token.function {
	color: #DD4A68;
}

.token.regex,
.token.important,
.token.variable {
	color: #e90;
}

.token.important,
.token.bold {
	font-weight: bold;
}
.token.italic {
	font-style: italic;
}

.token.entity {
	cursor: help;
}
</style>


</head>

<body>

<p>参考代码：<a href="http://git.oschina.net/crossin/crawler/blob/master/ex5_pyspider_jd_v1.py" target="_blank">http://git.oschina.net/crossin/crawler/blob/master/ex5_pyspider_jd_v1.py</a></p>

<h2 id="toc_0">1. 京东商品页</h2>

<p>抓取目标页面：</p>

<p><a href="https://m.jd.com/" target="_blank">https://m.jd.com/</a></p>

<p><img src="http://git.oschina.net/crossin/crawler/raw/master/stuff/jd.png" style="width:100%" alt="京东商品"></p>

<h2 id="toc_1">2. 内容来源</h2>

<p>爬虫采集数据的来源主要是网页和移动 App。</p>

<h3 id="toc_2">网页</h3>

<p>网页又分为 <strong>PC 页面</strong> 和 <strong>移动页面</strong>。通常来说，移动页面上的内容相对会更简洁、更易于抓取。</p>

<p>网页上显示的内容主要包括：</p>

<ul>
<li>网页 HTML 代码包含的内容</li>
<li>JavaScript 代码加载内容</li>
<li>Ajax 异步请求</li>
</ul>

<p>通过 Chrome 的开发者工具即可分析网页代码及发出的请求。</p>

<h3 id="toc_3">App</h3>

<p>大多数情况下，移动 App 中的信息为结构化文本，如 JSON 数据，更方便解析。</p>

<p>但 App 的数据抓取比网页复杂，通常需要使用抓包软件。如 Mac 上的 <strong>Charles</strong> 和 Windows 上的 <strong>Fiddler2</strong>。</p>

<h3 id="toc_4">参考资料</h3>

<ol>
<li><a href="http://www.csdn.net/article/2015-11-13/2826205" target="_blank">一看就明白的爬虫入门讲解：基础理论篇 - 孔淼</a></li>
</ol>

<h2 id="toc_5">3. pyspider</h2>

<p><strong>PySpider</strong>：一个国人编写的强大的网络爬虫系统并带有强大的 WebUI。采用 Python 语言编写，分布式架构，支持多种数据库后端，强大的 WebUI 支持脚本编辑器，任务监视器，项目管理器以及结果查看器。</p>

<p><a href="http://demo.pyspider.org/" target="_blank">在线示例</a></p>

<h3 id="toc_6">安装</h3>

<div><pre><code class="language-none">pip install pyspider</code></pre></div>

<h3 id="toc_7">启动</h3>

<p>安装成功后运行：</p>

<div><pre><code class="language-none">pyspider</code></pre></div>

<p>浏览器中打开 <code>http://localhost:5000/</code> 访问控制台</p>

<p><img src="http://git.oschina.net/crossin/crawler/raw/master/stuff/pyspider.png" style="width:100%" alt="pyspider webui"></p>

<h3 id="toc_8">编写脚本</h3>

<p>在 web 控制台点 <strong>create</strong> 按钮新建任务，项目名自定义。</p>

<p><img src="http://git.oschina.net/crossin/crawler/raw/master/stuff/create.png" style="width:100%" alt="create project"></p>

<p>保存后打开代码编辑器，默认生成基本代码。</p>

<p><img src="http://git.oschina.net/crossin/crawler/raw/master/stuff/file.png" style="width:100%" alt="new file"></p>

<p>在右侧代码编辑器中可编写自己的抓取脚本。</p>

<p>默认代码分析：</p>

<ul>
<li><strong>def on_start(self)</strong> 方法是入口代码。当在 web 控制台点击 run 按钮时会执行此方法。</li>
<li><strong>self.crawl(url, callback=self.index_page)</strong> 这个方法是调用 API 生成一个新的爬取任务，这个任务被添加到待抓取队列。</li>
<li><strong>def index_page(self, response)</strong> 这个方法获取一个 Response 对象。response.doc 是 pyquery 对象的一个扩展方法。pyquery 是一个类似于 jQuery 的对象选择器。</li>
<li><strong>def detail_page(self, response)</strong> 返回一个结果集对象。这个结果默认会被添加到 resultdb 数据库（如果启动时没有指定数据库默认调用 sqlite 数据库）。你也可以重写 on_result(self,result) 方法来指定保存位置。</li>
<li><strong>@every(minutes=24 * 60, seconds=0)</strong> 这个设置是告诉 scheduler（调度器）on_start 方法每天执行一次。</li>
<li><strong>@config(age=10 * 24 * 60 * 60)</strong> 这个设置告诉 scheduler（调度器）这个 request（请求）过期时间是 10 天，10 天内再遇到这个请求直接忽略。这个参数也可以在 self.crawl(url, age=10 * 24 * 60 * 60) 和 crawl_config 中设置。</li>
<li><strong>@config(priority=2)</strong> 这个是优先级设置。数字越大越先执行。</li>
</ul>

<h3 id="toc_9">执行</h3>

<p>点击 <strong>save</strong> 保存脚本，返回控制台首页。将项目状态 <strong>status</strong> 由 TODO 改为 DEBUG 或 RUNNING。点击项目右侧 <strong>Run</strong> 按钮启动项目。</p>

<p><img src="http://git.oschina.net/crossin/crawler/raw/master/stuff/run.png" style="width:100%" alt="run"></p>

<h3 id="toc_10">参考资料</h3>

<ol>
<li><a href="http://www.pyspider.cn/" target="_blank">    pyspider 中文网</a>
&gt;</li>
<li><a href="http://docs.pyspider.org/en/latest/" target="_blank">pyspider 官方文档</a></li>
<li><a href="https://segmentfault.com/t/pyspider" target="_blank">pyspider 中文问答 - SegmentFault</a></li>
</ol>

<h2 id="toc_11">4. 装饰器</h2>

<p>装饰器（Decorator）是 Python 提供的一种语法，可以在代码运行期间动态增加函数的功能。</p>

<p>本质上，decorator 就是返回另一个函数的函数。</p>

<h3 id="toc_12">示例</h3>

<p>我们有一个函数 timer，可以用来计算另一个函数调用的花费时间。</p>

<p>基本的写法：</p>

<div><pre><code class="language-python">import time

def timer(func):
    start = time.time()
    func()
    end = time.time()
    print(end - start)

def test():
    print(&#39;run test&#39;)
    time.sleep(1)

timer(test())</code></pre></div>

<p>输出：</p>

<div><pre><code class="language-none">run test
1.00250983238</code></pre></div>

<p>如果用装饰器，可以写成：</p>

<div><pre><code class="language-python">import time

def timer(func):
    def wrapper(*args, **kw):
        start = time.time()
        func(*args, **kw)
        end = time.time()
        print(end - start)
    return wrapper

@timer
def test():
    print(&#39;run test&#39;)
    time.sleep(1)

test()</code></pre></div>

<p>在上面的代码中，通过 Python 提供的 <code>@</code> 语法，给 <code>test()</code> 加上了装饰器 <code>@timer</code>。这时候，其实已经改变了 <code>test</code> 所对应的对象。</p>

<p>增加了装饰器后，在不改变原有函数内容和调用方法的情况下，增加了原有函数的功能（例子中为计时）。这种方式也易于扩展：所有需要此功能的函数，只要在函数声明前加上装饰器即可。</p>

<h3 id="toc_13">参考资料</h3>

<ol>
<li><a href="http://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/0014318435599930270c0381a3b44db991cd6d858064ac0000" target="_blank">装饰器 - 廖雪峰</a></li>
<li><a href="http://www.cnblogs.com/wilber2013/p/4657155.html" target="_blank">Python装饰器 - 田小计划</a></li>
</ol>

<h2 id="toc_14">5. 面向对象</h2>

<p>面向对象编程（Object Oriented Programming，简称 OOP）是一种程序设计思想。OOP 把对象作为程序的基本单元，一个对象包含了数据和操作数据的函数。</p>

<p>面向对象的相关内容在我们入门教程中有详细的讲述和练习。也可参考下面给出了参考资料链接。在这里仅简述一下主要的基本概念。</p>

<h3 id="toc_15">基本概念</h3>

<ul>
<li><p><strong>类(Class)</strong>：用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例。</p></li>
<li><p><strong>类变量</strong>：类变量在整个实例化的对象中是公用的。类变量定义在类中且在函数体之外。类变量通常不作为实例变量使用。</p></li>
<li><p><strong>数据成员</strong>：类变量或者实例变量用于处理类及其实例对象的相关的数据。</p></li>
<li><p><strong>方法重写</strong>：如果从父类继承的方法不能满足子类的需求，可以对其进行改写，这个过程叫方法的覆盖（override），也称为方法的重写。</p></li>
<li><p><strong>实例变量</strong>：定义在方法中的变量，只作用于当前实例的类。</p></li>
<li><p><strong>继承</strong>：即一个派生类（derived class）继承基类（base class）的字段和方法。继承也允许把一个派生类的对象作为一个基类对象对待。例如，有这样一个设计：一个 Dog 类型的对象派生自 Animal 类，这是模拟&quot;是一个（is-a）&quot;关系（例图，Dog 是一个 Animal）。</p></li>
<li><p><strong>实例化</strong>：创建一个类的实例，类的具体对象。</p></li>
<li><p><strong>方法</strong>：类中定义的函数。</p></li>
<li><p><strong>对象</strong>：通过类定义的数据结构实例。对象包括两个数据成员（类变量和实例变量）和方法。</p></li>
</ul>

<h3 id="toc_16">参考资料</h3>

<ol>
<li><a href="https://mp.weixin.qq.com/mp/appmsg/show?__biz=MjM5MDEyMDk4Mw==&amp;appmsgid=10000196&amp;itemidx=1&amp;sign=2176872b0086314a9463ccc811731cc4" target="_blank">编程教室：面向对象 1</a> | <a href="http://mp.weixin.qq.com/mp/appmsg/show?__biz=MjM5MDEyMDk4Mw==&amp;appmsgid=10000199&amp;itemidx=1&amp;sign=0e85961e537d8e1c8a6d65568ef7be54" target="_blank">面向对象 2</a> | <a href="http://mp.weixin.qq.com/mp/appmsg/show?__biz=MjM5MDEyMDk4Mw==&amp;appmsgid=10000202&amp;itemidx=1&amp;sign=bd57c81f02acd50318b66abe2b9bc120" target="_blank">面向对象 3</a> | <a href="http://mp.weixin.qq.com/mp/appmsg/show?__biz=MjM5MDEyMDk4Mw==&amp;appmsgid=10000209&amp;itemidx=1&amp;sign=e05cb29e0272f0a04aeeaede3d2272a6" target="_blank">面向对象 4</a></li>
<li><a href="http://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/0014318645694388f1f10473d7f416e9291616be8367ab5000" target="_blank">面向对象编程 - 廖雪峰</a></li>
<li><a href="http://www.runoob.com/python/python-object.html" target="_blank">Python 面向对象 - 菜鸟教程</a></li>
</ol>



<script type="text/javascript">
var _self="undefined"!=typeof window?window:"undefined"!=typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope?self:{},Prism=function(){var e=/\blang(?:uage)?-(\w+)\b/i,t=0,n=_self.Prism={util:{encode:function(e){return e instanceof a?new a(e.type,n.util.encode(e.content),e.alias):"Array"===n.util.type(e)?e.map(n.util.encode):e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/\u00a0/g," ")},type:function(e){return Object.prototype.toString.call(e).match(/\[object (\w+)\]/)[1]},objId:function(e){return e.__id||Object.defineProperty(e,"__id",{value:++t}),e.__id},clone:function(e){var t=n.util.type(e);switch(t){case"Object":var a={};for(var r in e)e.hasOwnProperty(r)&&(a[r]=n.util.clone(e[r]));return a;case"Array":return e.map&&e.map(function(e){return n.util.clone(e)})}return e}},languages:{extend:function(e,t){var a=n.util.clone(n.languages[e]);for(var r in t)a[r]=t[r];return a},insertBefore:function(e,t,a,r){r=r||n.languages;var l=r[e];if(2==arguments.length){a=arguments[1];for(var i in a)a.hasOwnProperty(i)&&(l[i]=a[i]);return l}var o={};for(var s in l)if(l.hasOwnProperty(s)){if(s==t)for(var i in a)a.hasOwnProperty(i)&&(o[i]=a[i]);o[s]=l[s]}return n.languages.DFS(n.languages,function(t,n){n===r[e]&&t!=e&&(this[t]=o)}),r[e]=o},DFS:function(e,t,a,r){r=r||{};for(var l in e)e.hasOwnProperty(l)&&(t.call(e,l,e[l],a||l),"Object"!==n.util.type(e[l])||r[n.util.objId(e[l])]?"Array"!==n.util.type(e[l])||r[n.util.objId(e[l])]||(r[n.util.objId(e[l])]=!0,n.languages.DFS(e[l],t,l,r)):(r[n.util.objId(e[l])]=!0,n.languages.DFS(e[l],t,null,r)))}},plugins:{},highlightAll:function(e,t){var a={callback:t,selector:'code[class*="language-"], [class*="language-"] code, code[class*="lang-"], [class*="lang-"] code'};n.hooks.run("before-highlightall",a);for(var r,l=a.elements||document.querySelectorAll(a.selector),i=0;r=l[i++];)n.highlightElement(r,e===!0,a.callback)},highlightElement:function(t,a,r){for(var l,i,o=t;o&&!e.test(o.className);)o=o.parentNode;o&&(l=(o.className.match(e)||[,""])[1],i=n.languages[l]),t.className=t.className.replace(e,"").replace(/\s+/g," ")+" language-"+l,o=t.parentNode,/pre/i.test(o.nodeName)&&(o.className=o.className.replace(e,"").replace(/\s+/g," ")+" language-"+l);var s=t.textContent,u={element:t,language:l,grammar:i,code:s};if(!s||!i)return n.hooks.run("complete",u),void 0;if(n.hooks.run("before-highlight",u),a&&_self.Worker){var c=new Worker(n.filename);c.onmessage=function(e){u.highlightedCode=e.data,n.hooks.run("before-insert",u),u.element.innerHTML=u.highlightedCode,r&&r.call(u.element),n.hooks.run("after-highlight",u),n.hooks.run("complete",u)},c.postMessage(JSON.stringify({language:u.language,code:u.code,immediateClose:!0}))}else u.highlightedCode=n.highlight(u.code,u.grammar,u.language),n.hooks.run("before-insert",u),u.element.innerHTML=u.highlightedCode,r&&r.call(t),n.hooks.run("after-highlight",u),n.hooks.run("complete",u)},highlight:function(e,t,r){var l=n.tokenize(e,t);return a.stringify(n.util.encode(l),r)},tokenize:function(e,t){var a=n.Token,r=[e],l=t.rest;if(l){for(var i in l)t[i]=l[i];delete t.rest}e:for(var i in t)if(t.hasOwnProperty(i)&&t[i]){var o=t[i];o="Array"===n.util.type(o)?o:[o];for(var s=0;s<o.length;++s){var u=o[s],c=u.inside,g=!!u.lookbehind,h=!!u.greedy,f=0,d=u.alias;u=u.pattern||u;for(var p=0;p<r.length;p++){var m=r[p];if(r.length>e.length)break e;if(!(m instanceof a)){u.lastIndex=0;var y=u.exec(m),v=1;if(!y&&h&&p!=r.length-1){var b=r[p+1].matchedStr||r[p+1],k=m+b;if(p<r.length-2&&(k+=r[p+2].matchedStr||r[p+2]),u.lastIndex=0,y=u.exec(k),!y)continue;var w=y.index+(g?y[1].length:0);if(w>=m.length)continue;var _=y.index+y[0].length,P=m.length+b.length;if(v=3,P>=_){if(r[p+1].greedy)continue;v=2,k=k.slice(0,P)}m=k}if(y){g&&(f=y[1].length);var w=y.index+f,y=y[0].slice(f),_=w+y.length,S=m.slice(0,w),O=m.slice(_),j=[p,v];S&&j.push(S);var A=new a(i,c?n.tokenize(y,c):y,d,y,h);j.push(A),O&&j.push(O),Array.prototype.splice.apply(r,j)}}}}}return r},hooks:{all:{},add:function(e,t){var a=n.hooks.all;a[e]=a[e]||[],a[e].push(t)},run:function(e,t){var a=n.hooks.all[e];if(a&&a.length)for(var r,l=0;r=a[l++];)r(t)}}},a=n.Token=function(e,t,n,a,r){this.type=e,this.content=t,this.alias=n,this.matchedStr=a||null,this.greedy=!!r};if(a.stringify=function(e,t,r){if("string"==typeof e)return e;if("Array"===n.util.type(e))return e.map(function(n){return a.stringify(n,t,e)}).join("");var l={type:e.type,content:a.stringify(e.content,t,r),tag:"span",classes:["token",e.type],attributes:{},language:t,parent:r};if("comment"==l.type&&(l.attributes.spellcheck="true"),e.alias){var i="Array"===n.util.type(e.alias)?e.alias:[e.alias];Array.prototype.push.apply(l.classes,i)}n.hooks.run("wrap",l);var o="";for(var s in l.attributes)o+=(o?" ":"")+s+'="'+(l.attributes[s]||"")+'"';return"<"+l.tag+' class="'+l.classes.join(" ")+'" '+o+">"+l.content+"</"+l.tag+">"},!_self.document)return _self.addEventListener?(_self.addEventListener("message",function(e){var t=JSON.parse(e.data),a=t.language,r=t.code,l=t.immediateClose;_self.postMessage(n.highlight(r,n.languages[a],a)),l&&_self.close()},!1),_self.Prism):_self.Prism;var r=document.currentScript||[].slice.call(document.getElementsByTagName("script")).pop();return r&&(n.filename=r.src,document.addEventListener&&!r.hasAttribute("data-manual")&&document.addEventListener("DOMContentLoaded",n.highlightAll)),_self.Prism}();"undefined"!=typeof module&&module.exports&&(module.exports=Prism),"undefined"!=typeof global&&(global.Prism=Prism);
</script>

<script type="text/javascript">
Prism.languages.python={"triple-quoted-string":{pattern:/"""[\s\S]+?"""|'''[\s\S]+?'''/,alias:"string"},comment:{pattern:/(^|[^\\])#.*/,lookbehind:!0},string:/("|')(?:\\?.)*?\1/,"function":{pattern:/((?:^|\s)def[ \t]+)[a-zA-Z_][a-zA-Z0-9_]*(?=\()/g,lookbehind:!0},"class-name":{pattern:/(\bclass\s+)[a-z0-9_]+/i,lookbehind:!0},keyword:/\b(?:as|assert|async|await|break|class|continue|def|del|elif|else|except|exec|finally|for|from|global|if|import|in|is|lambda|pass|print|raise|return|try|while|with|yield)\b/,"boolean":/\b(?:True|False)\b/,number:/\b-?(?:0[bo])?(?:(?:\d|0x[\da-f])[\da-f]*\.?\d*|\.\d+)(?:e[+-]?\d+)?j?\b/i,operator:/[-+%=]=?|!=|\*\*?=?|\/\/?=?|<[<=>]?|>[=>]?|[&|^~]|\b(?:or|and|not)\b/,punctuation:/[{}[\];(),.:]/};
</script>


</body>

</html>
